<template>
	<view class="e-form-item">
		<view class="e-form-item__body" @tap="clickHandler" :style="contentStyle">
			<!-- 微信小程序中，将一个参数设置空字符串，结果会变成字符串"true" -->
			<slot name="label">
				<view class="e-form-item__body__left" v-if="props.required || props.leftIcon || props.label"
					:style="leftStyle">
					<!-- 为了块对齐 -->
					<view class="e-form-item__body__left__content">
						<!-- nvue不支持伪元素before -->
						<text v-if="props.required&&requiredPosition === 'left'"
							class="e-form-item__body__left__content__required">*</text>
						<view class="e-form-item__body__left__content__icon" v-if="props.leftIcon">
							<e-icon :name="props.leftIcon" :custom-style="props.leftIconStyle"></e-icon>
						</view>
						<text class="e-form-item__body__left__content__label" :style="labelStyle">
							{{ props.label }}
						</text>
						<text v-if="props.required&&requiredPosition === 'right'"
							class="e-form-item__body__left__content__required">*</text>
					</view>
				</view>
			</slot>
			<view class="e-form-item__body__right">
				<view class="e-form-item__body__right__content">
					<view class="e-form-item__body__right__content__slot">
						<slot />
					</view>
					<view class="e-form-item__body__right__content__icon" v-if="$slots.right">
						<slot name="right" />
					</view>
				</view>
			</view>
		</view>
		<slot name="error">
			<text v-if="!!message && formContext.props.errorType === 'message'" class="e-form-item__error"
				:style="[errorStyle]">
				{{ message }}
			</text>
		</slot>
		<e-line v-if="borderBottomShow"
			:color="message && formContext.props.errorType === 'border-bottom' ? config.color.error : '#d6d7d9'"
			:customStyle="`margin-top: ${message&& formContext.props.errorType === 'message' ? '5px' : 0}`"></e-line>
	</view>
</template>
<script lang="ts">
	import {
		defineComponent
	} from 'vue'
	import mpMixin from "../../libs/mixin/mpMixin";
	
	/**
	 * Form 表单
	 * @description 此组件一般用于表单场景，可以配置Input输入框，Select弹出框，进行表单验证等。
	 * @tutorial https://www.uviewui.com/components/form.html
	 * @property {String}			label			 input的label提示语
	 * @property {String}			prop			 绑定的值
	 * @property {String}			labelPosition	 表单域提示文字的位置，left-左侧，top-上方 ( 默认 'left' ）
	 * @property {String | Boolean}	borderBottom	 是否显示表单域的下划线边框
	 * @property {String | Number}	labelWidth		 label的宽度，单位px
	 * @property {String}			rightIcon		 右侧图标
	 * @property {String}			leftIcon		 左侧图标
	 * @property {String | Object} 	leftIconStyle 	 左侧图标的样式
	 * @property {Boolean}			required		 是否显示左边的必填星号，只作显示用，具体校验必填的逻辑，请在rules中配置 (默认 false )
	 * @property {String}			requiredPosition 星号位置，left左边，right右边
	 *
	 * @example <e-form-item label="姓名" prop="userInfo.name" borderBottom ref="item1"></e-form-item>
	 */
	export default defineComponent({
		name: 'e-form-item',
		mixins: [mpMixin]
	})
</script>
<script lang="ts" setup>
	import {
		ref,
		computed,
		reactive,
		toRefs,
		provide,
		inject,
		onMounted,
		onBeforeUnmount,
		nextTick
	} from 'vue'
	import {
		formItemProps,
		formItemEmits
	} from './props'
	import {
		formContextKey,
		type FormItemContext,
		formItemContextKey
	} from '../../libs/tokens'
	import {
		getProperty,
		setProperty,
		isUndefined,
		isNull
	} from '../../libs/utils'
	import {
		useDefaultProps
	} from '../../libs/hooks'
	import {
		throwError,
		addUnit,
		addStyle
	} from '../../libs/utils/_utils'
	import {
		config
	} from '../../libs/config'
	import componentsProps from "../../libs/config/componentsProps";
	import type {
		 FormItemProps
	} from "../../libs/config/propsType";


	const {
		formItem: formItemDefaultProps
	} = toRefs(componentsProps)

	const _props = defineProps(formItemProps)
	const props = useDefaultProps < FormItemProps > (_props, formItemDefaultProps);
	const emit = defineEmits(formItemEmits)
	const formContext = inject(formContextKey)
	if (!formContext) throwError('EFormItem', 'e-form-item需要结合e-form组件使用')

	const message = ref('')

	const labelPosition = computed(() => props.value.labelPosition || formContext.props.labelPosition)

	const leftStyle = computed(() => {

		const labelWidth = addUnit(props.value.labelWidth as string || formContext.props.labelWidth as string)
		return {
			width: labelWidth,
			marginBottom: labelPosition.value === 'left' ? 0 : '5px'
		}

	})
	const requiredPosition = computed(() => props.value.requiredPosition || formContext.props.requiredPosition || 'left')
	const labelStyle = computed(() => {
		return [
			formContext.props.labelStyle,
			{
				justifyContent: formContext.props.labelAlign === 'left' ? 'flex-start' : formContext.props.labelAlign ===
					'center' ? 'center' : 'flex-end'
			}
		]

	})
	const contentStyle = computed(() => {
		return [
			addStyle(props.value.customStyle),
			{
				flexDirection: labelPosition.value === 'left' ? 'row' : 'column',
				alignItems: labelPosition.value === 'left' ? '' : 'stretch',
			}
		]
	})
	const errorStyle = computed(() => {

		const labelWidth = addUnit(props.value.labelWidth as string || formContext.props.labelWidth as string)
		return {
			marginLeft: labelWidth
		}

	})
	const borderBottomShow = computed(() => {
		return (isUndefined(props.value.borderBottom)||isNull(props.value.borderBottom)) ? formContext.props.borderBottom : props.value.borderBottom
	})
	// 移除form-item的校验结果
	const clearValidate = () => {
		message.value = ''
	}
	// 清空当前的组件的校验结果，并重置为初始值
	const resetField: FormItemContext['resetField'] = async () => {
		const model = formContext.props.model
		if (!model || !props.value.prop) return

		const computedValue = getProperty < any > (formContext.originalModel, props.value.prop)
		// 重置为初始值
		setProperty(model, props.value.prop, computedValue)

		await nextTick()
		clearValidate()
	}

	// 点击组件
	const clickHandler = () => {
		emit('click')
	}

	const context: FormItemContext = reactive({
		props,
		message,
		resetField,
		clearValidate,
		clickHandler
	})

	onMounted(() => {
		if (props.value.prop) {
			formContext.addField(context)
		}
	})
	onBeforeUnmount(() => {
		formContext.removeField(context)
	})
	provide(formItemContextKey, context)

	defineExpose({
		/** @description clear validation status */
		clearValidate,
		/** @description reset field value */
		resetField,
		/** @description click components */
		clickHandler,
	})
</script>

<style lang="scss" scoped>
	@import '../../libs/theme/form-item.scss';
</style>
